<script setup>
import {colorRgb, HSVtoRGB, hue2RGB, rgb2Hex, rgbtohsv, throttle} from "./colorUtil";
import {ref, reactive, watch, nextTick, getCurrentInstance} from "vue";

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
});

const emit = defineEmits(["change", "confirm", "update:modelValue"]);

const colorPickerShow = ref(false);

const hColor = ref("#f00");
const hue = ref(0);

const currentInstance = getCurrentInstance();

let svWidth = 0;
let svHeight = 0;
let svRect = { top: 0, left: 0, width: 0, height: 0 };
let hRect = { top: 0, left: 0, width: 0, height: 0 };
const svPoint = reactive({
  x: 0,
  y: 0,
});

const hPoint = reactive({
  x: 0,
  y: 0,
});

let hHeight = 0;
let hWidth = 0;

const ultimatelyColor = ref("#FF0000");

function getNodeRect(selector) {
  return new Promise((resolve) => {
    const query = uni.createSelectorQuery().in(currentInstance);
    query
      .selectAll(selector)
      .boundingClientRect((res) => {
        resolve(res);
      })
      .exec();
  });
}

const init = async () => {
  const nodes = await getNodeRect(".sv,.hue");
  svRect = nodes[0];
  // console.log(svRect);
  svHeight = svRect.height;
  svWidth = svRect.width;
  hRect = nodes[1];
  hHeight = hRect.height;
  hWidth = hRect.width;
};

const curChange = (e) => {
  const { x, y } = e.detail;
  hue.value = (x / hWidth) * 360;
  const hrgb = hue2RGB(hue.value);
  hColor.value = hrgb;
  const rgb = HSVtoRGB(
    hue.value,
    svPoint.x / svWidth,
    1 - svPoint.y / svHeight
  );
  ultimatelyColor.value = rgb2Hex(rgb).toUpperCase();
  emit("change", ultimatelyColor.value);
  emit("update:modelValue", ultimatelyColor.value);
  // console.log(rgb);
};
const hClick = (e) => {
  const { x, y } = e.detail;
  hPoint.x = x - hRect.left;
};

//限流函数
const svChangeSetColor = throttle(() => {
  const rgb = HSVtoRGB(
    hue.value,
    svPoint.x / svWidth,
    1 - svPoint.y / svHeight
  );
  ultimatelyColor.value = rgb2Hex(rgb).toUpperCase();
  emit("change", ultimatelyColor.value);
  emit("update:modelValue", ultimatelyColor.value);
}, 10);

const svChange = (e) => {
  // console.log('svChange',e)
  const { x, y, source } = e.detail;
  if (source !== "touch") {
    return;
  }
  svPoint.x = x;
  svPoint.y = y;
  svChangeSetColor();
};

const svClick = (e) => {
  console.log(e);
  const { x, y } = e.detail;
  svPoint.x = x - svRect.left;
  svPoint.y = y - svRect.top;

  const rgb = HSVtoRGB(
    hue.value,
      svPoint.x / svWidth,
    1 - svPoint.y / svHeight
  );
  ultimatelyColor.value = rgb2Hex(rgb).toUpperCase();
  emit("update:modelValue", ultimatelyColor.value);
};

const open = () => {
  colorPickerShow.value = true;
  setTimeout(() => {
    nextTick(async () => {
      await init();
      ultimatelyColor.value = props.modelValue || ultimatelyColor.value;
      colorToXy();
    });
  }, 100);
};

const close = () => {
  colorPickerShow.value = false;
};
const confirm = () => {
  emit("confirm", ultimatelyColor.value);
  emit("update:modelValue", ultimatelyColor.value);
  close();
};

const inputColor = (e) => {
  var reg = /^#[0-9a-fA-f]{6,8}$/;
  if(!reg.test(e)){
    return;
  }
  ultimatelyColor.value = e;
  emit("update:modelValue", ultimatelyColor.value);
  colorToXy();
};

const colorToXy = () => {
  let rgb = colorRgb(ultimatelyColor.value);
  console.log(rgb,'rgb')
  const hsv = rgbtohsv(...rgb);
  console.log(hsv,'hsv')
  hPoint.x = hsv[0]/360 * hWidth;
  svPoint.x =  hsv[1]/100 * svWidth;
  svPoint.y = (1 - hsv[2]/100) * svHeight;
};

const clearColor = () => {
  emit("update:modelValue", '');
};

</script>

<template>
  <view class="color-picker-box" tabindex="1" @blur="close">
<!--    <view class="mask" v-if="colorPickerShow" @click="close"></view>-->
      <view style="cursor:pointer;" >
        <slot name="default">
          <view v-if="modelValue">
            <view style="display: flex;align-items: center">
              <view class="color-picker-cur-color-modelValue">
                <view @click="open"
                      class="cur-color"
                      :style="{ backgroundColor: modelValue }"
                ></view>
                <input class="cur-color-value" :value="modelValue" @update:modelValue="inputColor"/>
                <view v-if="modelValue" class="clear-color" @click="clearColor">X</view>
              </view>

            </view>

          </view>
          <view @click="open" v-else class="no-set-color">
            未设置颜色
          </view>
        </slot>

      </view>

    <view class="color-picker-wrap" :class="{ open: colorPickerShow }">
      <view class="color-picker">
        <view class="color-picker-sv">
          <view class="color-picker-sv-canvas">
            <!-- 对比度和明度的矩形 -->
            <movable-area class="sv-area" @click="svClick">
              <view class="sv-bg">
                <view class="sv" :style="{ background: hColor }">
                  <view class="s-mask">
                    <view class="v-mask"></view>
                  </view>
                </view>
              </view>

              <movable-view
                  :x="svPoint.x"
                  :y="svPoint.y"
                  class="sv-move"
                  @change="svChange"
                  :animation="false"
                  direction="all"
              ></movable-view>
            </movable-area>
          </view>
        </view>
        <view class="color-picker-h">
          <view class="color-picker-cur-color-canvas">
            <movable-area style="width: 100%; height: 100%" @click="hClick">
              <view class="hue-bg">
                <view class="hue"> </view>
              </view>

              <movable-view
                  :x="hPoint.x"
                  :y="hPoint.y"
                  class="sv-move"
                  @change="curChange"
                  :animation="false"
                  direction="all"
              ></movable-view>
            </movable-area>
          </view>
          <view class="color-picker-cur-color">
            <view
                class="cur-color"
                :style="{ backgroundColor: ultimatelyColor }"
            ></view>
            <view class="cur-color-value">{{ ultimatelyColor }}</view>
          </view>
        </view>
      </view>
      <view class="ops-btns">
        <view class="close" @click="close">
          关闭
        </view>
        <view>自定义颜色</view>
        <view class="confirm" @click="confirm">
          确定
        </view>
      </view>
    </view>
  </view>

</template>

<style scoped lang="scss">
.color-picker-box{
  position: relative;
  width: 800rpx;
  .no-set-color{
    color: #7f7f7f;
  }
}

.color-picker-wrap{
  position: absolute;
  bottom: 0;
  left: 0;
  transition: 300ms;
  width: 800rpx;
  opacity: 0;
  z-index: -1;
  transform: translateY(100%);
  display: flex;
  flex-direction: column;
}
.color-picker-wrap.open{
  opacity: 1;
  z-index: 2;
  background: #ffffff;
  box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.8);
  border-radius: 10rpx;
  overflow: hidden;
  transform: translateY(calc(100% + 10rpx));
}

.color-picker {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  background: #FFFFFF;

  padding: 20rpx;
  .hue {
    height: 30rpx;
    /* 色相：从左到右依次为 红、黄、绿、青、蓝、洋红，等分渐变 */
    background: linear-gradient(
      to right,
      #f00 0%,
      #ff0 17%,
      #0f0 33%,
      #0ff 50%,
      #00f 67%,
      #f0f 83%,
      #f00 100%
    );
  }
  .s-mask {
    width: 100%;
    height: 100%;
    /* 饱和度x轴实现：从左到右，纯白 >>> 透明的渐变 */
    background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
  }
  .v-mask {
    width: 100%;
    height: 100%;
    /* 明度y轴的实现：从下到上，纯黑 >>> 透明的渐变 */
    background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
  }
  .color-picker-sv {
    width: 100%;
    height: 300rpx;
    display: flex;
    .color-picker-sv-canvas {
      flex: 1;
      display: flex;
      .sv {
        width: 100%;
        height: 100%;
        border-radius: 10rpx;
        overflow: hidden;
      }

      .sv-area {
        width: 100%;
        height: 100%;
      }
      .sv-bg {
        height: 100%;
        padding: 20rpx;
        box-sizing: border-box;
      }
      .sv-move {
        width: 40rpx;
        height: 40rpx;
        box-sizing: border-box;
        border: 4rpx solid #fff;
        border-radius: 40rpx;
        background: #ffffff00;
      }
    }
  }

  .color-picker-h {
    padding: 0 20rpx;
    box-sizing: border-box;
    margin-top: 20rpx;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    .color-picker-cur-color-canvas {
      flex: 1;
      height: 30rpx;
      transform: translateX(-15rpx);
      .hue {
        width: calc(100% - 30rpx);
        transform: translateX(15rpx);
        border-radius: 30rpx;
        overflow: hidden;
      }
      .sv-move {
        width: 30rpx;
        height: 30rpx;
        background: #00000000;
        border-radius: 30rpx;
        border: 4rpx solid #fff;
        box-sizing: border-box;
      }
    }
    .color-picker-cur-color {
      display: flex;
      align-items: center;
      padding: 14rpx 20rpx;
      margin-left: 20rpx;
      border: 2rpx solid #f2f2f2;
      border-radius: 10rpx;
      .cur-color {
        width: 40rpx;
        height: 40rpx;
        border: 2rpx solid #f2f2f2;
        border-radius: 10rpx;
        margin-right: 10rpx;
      }
      .cur-color-value {
        font-size: 34rpx;
        width: 140rpx;
      }
    }
  }
}
.clear-color{
  margin-left: 10rpx;
}
.color-picker-cur-color-modelValue {
  display: flex;
  align-items: center;
  padding: 14rpx 20rpx;
  border: 2rpx solid #f2f2f2;
  border-radius: 10rpx;
  .cur-color {
    width: 40rpx;
    height: 40rpx;
    border: 2rpx solid #f2f2f2;
    border-radius: 10rpx;
    margin-right: 10rpx;
  }
  .cur-color-value {
    font-size: 34rpx;
  }
}
.ops-btns {
  display: flex;
  justify-content: space-between;
  border-top: 2rpx #f2f2f2 solid;
  padding: 20rpx 40rpx;
  color: #000000;


  .confirm {
    text-align: right;
    color: #007aff;
    .mpInfo-icon {
      font-size: 40rpx;
    }
  }
}
</style>
